﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using JpegEncoder;

namespace LockScreenSwitcher
{
    class Program
    {
        static void Main(string[] args)
        {

            string sourceDirectorySetting;
            string destinationDirectorySetting;
            DirectoryInfo sourceDirectory;
            DirectoryInfo destinationDirectory;
            int imageWidth;
            int imageHeight;

            if (!int.TryParse(ConfigurationSettings.AppSettings["ImageWidth"], out imageWidth))
            {
                imageWidth = 0;
            }

            if (!int.TryParse(ConfigurationSettings.AppSettings["ImageHeight"], out imageHeight))
            {
                imageHeight = 0;
            }

            destinationDirectorySetting = ConfigurationSettings.AppSettings["DestinationFolder"];
            if (destinationDirectorySetting != null)
            {
                destinationDirectorySetting = IoHelper.ExpandEnvironmentAndSpecialFolderPaths(destinationDirectorySetting);

                if (!IoHelper.DirectoryExists(destinationDirectorySetting))
                {
                    IoHelper.CreateDirectory(destinationDirectorySetting);
                }
                
                if (IoHelper.DirectoryExists(destinationDirectorySetting))
                {
                    destinationDirectory = new DirectoryInfo(destinationDirectorySetting);
                }
                else
                {
                    Console.WriteLine("No such destination directory, \"{0}\"", destinationDirectorySetting);
                    return;
                }
            }
            else
            {
                Console.WriteLine("No SourceFolder setting found!");
                return;
            }

            List<string> sourceFilePaths = null;

            sourceDirectorySetting = ConfigurationSettings.AppSettings["SourceFolder"];
            if (sourceDirectorySetting != null)
            {
                sourceDirectorySetting = IoHelper.ExpandEnvironmentAndSpecialFolderPaths(sourceDirectorySetting);

                if (IoHelper.DirectoryExists(sourceDirectorySetting))
                {
                    sourceDirectory = new DirectoryInfo(sourceDirectorySetting);
                    string[] fileExtensions = {".jpg", ".jpeg", ".png", ".bmp"};
                    sourceFilePaths = FindImageFiles(sourceDirectory.FullName, fileExtensions, imageWidth, imageHeight);
                }
                else
                {
                    Console.WriteLine("No such source directory, \"{0}\"", sourceDirectorySetting);
                    return;
                }
            }
            else
            {
                Console.WriteLine("No DestinationFolder setting found!");
                return;
            }

            if (sourceFilePaths.Count > 0)
            {
                // Pick a random image
                Random rnd = new Random();
                int imageIndex = rnd.Next(0, sourceFilePaths.Count - 1);

                string sourceImageFilePath = sourceFilePaths[imageIndex];

                // Construct the full name (path) of the destination file.
                string destinationFileFullName = Path.Combine(destinationDirectory.FullName, "backgroundDefault.jpg");

                // If the destination file exists, delete it.
                if (File.Exists(destinationFileFullName))
                {
                    File.SetAttributes(destinationFileFullName, FileAttributes.Normal);
                    File.Delete(destinationFileFullName);
                }

                SaveToBackgroundFile(sourceImageFilePath, destinationFileFullName, 244000);
            }

        }

        public static void SaveToBackgroundFile(string sourceImageFilePath, string destinationFileFullName, long maxFileSize)
        {
            int quality = 10;
            int saveCount = 0;
            // Load the source image, then save it to the destination folder

            string tempFilePath = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".jpg";
            using (Image newImage = System.Drawing.Image.FromFile(sourceImageFilePath))
            {
                WriteTraceMessage(string.Format("Loaded {0}", sourceImageFilePath));
                FileInfo oldImageFile = new FileInfo(sourceImageFilePath);
                oldImageFile.Refresh();
                WriteTraceMessage(string.Format("{0} size is {1} bytes.", sourceImageFilePath, oldImageFile.Length));

                WriteTraceMessage(string.Format("Writing {0} with quality of 10.", tempFilePath));
                ImageHelper.SaveAsJpeg(newImage, tempFilePath, 10);
                saveCount++;

                FileInfo newImageFile = new FileInfo(tempFilePath);
                newImageFile.Refresh();

                WriteTraceMessage(string.Format("{0} size is {1} bytes.", tempFilePath, newImageFile.Length));
                
                while (newImageFile.Length >= maxFileSize || newImageFile.Length == 0)
                {
                    // Decrease quality by 10 + a number proportional to the difference between the new, saved image file size and the max file size.
                    quality += (10 + (int)((newImageFile.Length - maxFileSize) / 8000));
                    WriteTraceMessage(string.Format("Writing {0} with quality of {1}.", tempFilePath, quality));
                    ImageHelper.SaveAsJpeg(newImage, tempFilePath, quality);
                    newImageFile.Refresh();
                    WriteTraceMessage(string.Format("{0} size is {1} bytes.", tempFilePath, newImageFile.Length));
                    saveCount++;
                    WriteTraceMessage(string.Format("# of save attempts: {0}", saveCount));
                    
                }

                File.Copy(tempFilePath, destinationFileFullName, true);
                WriteTraceMessage(string.Format("Copied {0} to {1}", tempFilePath, destinationFileFullName));
                File.Delete(tempFilePath);
                WriteTraceMessage(string.Format("Deleted {0}", tempFilePath));
            }
            
        }

        public static List<string> FindImageFiles(string rootDirectory, string[] fileExtensions, int width, int height)
        {
            DirectoryInfo sourceDirectory = new DirectoryInfo(rootDirectory);

            FileInfo[] sourceFiles = sourceDirectory.GetFilesByExtensions(fileExtensions).ToArray();
            List<string> sourceFilePaths = new List<string>();
            for (int counter = 0; counter < sourceFiles.Length; counter++)
            {
                Size imageSize = ImageHelper.GetDimensions(sourceFiles[counter].FullName);

                bool addThisImage = true;
                bool checkWidth = width > 0;
                bool checkHeight = height > 0;

                if (checkWidth | checkHeight)
                {
                    if (checkWidth)
                    {
                        if (imageSize.Width != width)
                        {
                            addThisImage = false;
                        }
                    }
                    if (checkHeight)
                    {
                        if (imageSize.Height != height)
                        {
                            addThisImage = false;
                        }
                    }
                    
                }
                
                if (addThisImage)
                {
                    sourceFilePaths.Add(sourceFiles[counter].FullName);
                }
            }
            return sourceFilePaths;
        }

        public static void WriteTraceMessage(string message)
        {

            Trace.TraceInformation(string.Format("{0} {1}", DateTime.Now.ToString("o"), message));
            Trace.Flush();

        }
        
    }
}
